#!/bin/sh
exec -a http_file_service python3 - "$@" << EOF
# 
# python
import os
import sys
import argparse
import signal
import logging
import threading
from datetime import datetime
from http.server import HTTPServer, SimpleHTTPRequestHandler
from socketserver import ThreadingMixIn

class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
    daemon_threads = True
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._shutdown_lock = threading.Lock()
        self._is_shutdown = False
        self._shutdown_notify = threading.Condition(self._shutdown_lock)

    def shutdown(self):
        """完全线程安全的关闭方法"""
        with self._shutdown_lock:
            if self._is_shutdown:
                return
            self._is_shutdown = True
            self._shutdown_notify.notify_all()

        # 使用非阻塞方式关闭socket
        self.socket.close()
        super().shutdown()



class FileDownloadHandler(SimpleHTTPRequestHandler):
    def __init__(self, *args, root_dir=None, **kwargs):
        if root_dir is None:
            root_dir = os.getcwd()
        self.root_dir = os.path.abspath(root_dir)
        super().__init__(*args, directory=self.root_dir, **kwargs)
        
    def log_message(self, format, *args):
        """重写日志方法统一使用logging模块"""
        logging.info("%s - - [%s] %s" % (
            self.address_string(),
            self.log_date_time_string(),
            format%args
        ))

    def do_GET(self):
        """处理GET请求并添加访问日志"""
        path = self.translate_path(self.path)
        client_ip, client_port = self.client_address[0], self.client_address[1]

        # 安全检查1：路径回溯检测
        try:
            rel_path = os.path.relpath(path, self.root_dir)
            if rel_path.startswith('..'):
                logging.warning(f"路径回溯检测 [客户端 {client_ip}:{client_port}]: {rel_path}")
                self.send_error(403, "Forbidden")
                return
        except ValueError:
            logging.warning(f"非法路径访问 [客户端 {client_ip}:{client_port}]: {path}")
            self.send_error(400, "Invalid URL path")
            return

        # 安全检查2：禁止目录访问
        if os.path.isdir(path):
            logging.warning(f"目录访问尝试 [客户端 {client_ip}:{client_port}]: {path}")
            self.send_error(403, "Directory listing denied")
            return

        # 文件存在性检查
        if not os.path.isfile(path):
            logging.warning(f"文件不存在 [客户端 {client_ip}:{client_port}]: {os.path.relpath(path, self.root_dir)}")
            self.send_error(404, "File not found")
            return

        # 文件下载日志
        logging.info(f"文件下载开始 [客户端 {client_ip}:{client_port}]: {os.path.relpath(path, self.root_dir)}")
        
        try:
            self.send_response(200)
            self.send_header("Content-Type", "application/octet-stream")
            self.send_header("Content-Disposition", 
                           f'attachment; filename="{os.path.basename(path)}"')
            self.send_header("Content-Length", os.path.getsize(path))
            self.end_headers()
            
            # 优化大文件传输
            with open(path, 'rb') as f:
                while True:
                    data = f.read(64 * 1024)  # 64KB分块传输
                    if not data:
                        break
                    self.wfile.write(data)
            logging.info(f"文件下载完成 [客户端 {client_ip}:{client_port}]: {os.path.relpath(path, self.root_dir)}")
            
        except ConnectionAbortedError:
            logging.warning(f"连接中断 [客户端 {client_ip}:{client_port}]")


def setup_logging(logfile=None):
    """配置带实时刷新的日志系统"""
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    # 清空现有处理器
    for handler in logger.handlers[:]:
        logger.removeHandler(handler)
    if logfile:
        # 确保日志目录存在
        os.makedirs(os.path.dirname(logfile), exist_ok=True)
        
        # 使用无缓冲模式（0=unbuffered）
        file_handler = logging.FileHandler(
            logfile, 
            encoding='utf-8', 
            mode='w', 
            delay=False
        )
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)
    else:
        # 控制台输出自动带实时刷新
        stream_handler = logging.StreamHandler(sys.stdout)
        stream_handler.setFormatter(formatter)
        logger.addHandler(stream_handler)
    def flush_all():
        """强制刷新所有日志处理器"""
        for handler in logger.handlers:
            handler.flush()
            if isinstance(handler, logging.FileHandler):
                os.fsync(handler.stream.fileno())
    
    return flush_all


def create_signal_handler(server, flush_func):
    def handler(sig, frame):
        if not hasattr(server, '_is_shutdown'):  # 防御性检查
            os._exit(1)
        
        signame = {
            signal.SIGINT: 'SIGINT',
            signal.SIGTERM: 'SIGTERM'
        }.get(sig, str(sig))

        try:
            #
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
            logging.info(
                f"\n[{timestamp}] 进程 {os.getpid()} 收到 {signame} 信号"
                f"\n关闭服务器......"
            )

            # 直接关闭socket解除阻塞
            server.socket.close()
            
            # 标记关闭状态（通过线程安全属性）
            if hasattr(server, '_shutdown_notify'):
                with server._shutdown_lock:
                    server._is_shutdown = True
                    server._shutdown_notify.notify_all()

        except Exception as e:
            logging.error(f"停止过程中发生异常: {str(e)}")
        finally:
            os._exit(0)  # 立即退出
    return handler

def main():
    # 命令行参数配置
    parser = argparse.ArgumentParser(description='文件下载服务器')
    parser.add_argument('--port', type=int, default=8000,
                       help='服务端口（默认：8000）')
    parser.add_argument('--dir', required=True,
                       help='文件目录（必须指定）')
    parser.add_argument('--logfile',
                       help='日志文件路径（默认输出到终端）')
    args = parser.parse_args()

    # 日志配置 - 解决encoding参数问题
    flush_logs = setup_logging(args.logfile)
    
    # 目录验证
    if not os.path.isdir(args.dir):
        logging.critical(f"错误：目录不存在 '{os.path.abspath(args.dir)}'")
        sys.exit(1)

    # 服务器初始化
    server_address = ('', args.port)
    handler = lambda *a, **k: FileDownloadHandler(*a, root_dir=args.dir, **k)
    server = ThreadingHTTPServer(server_address, handler)
    
    # 注册所有常见终止信号
    signal_handler = create_signal_handler(server, flush_logs)
    for sig in [signal.SIGINT, signal.SIGTERM, signal.SIGQUIT]:
        signal.signal(sig, signal_handler)
    
    # 服务器启动信息
    host_info = f"http://localhost:{args.port}" if args.port != 80 else "http://localhost"
    logging.info(f"服务器启动成功\n"
                f"文件目录: {os.path.abspath(args.dir)}\n"
                f"访问地址: {host_info}/your_file.ext")

    # 优雅退出处理
    try:
        with server:
            server.serve_forever(poll_interval=0.5)  # 更短的轮询间隔
    except KeyboardInterrupt:
        server.shutdown()
    except Exception as e:
        logging.critical(f"服务器错误: {e}", exc_info=True)

if __name__ == '__main__':
    main()

EOF